package com.lzt.app

import java.util
import java.util.{Collections}
import org.atmosphere.cpr.AtmosphereResource
import org.json4s.JsonDSL._
import org.json4s._
import org.scalatra._
import org.scalatra.atmosphere._
import org.scalatra.json.{JValueResult, JacksonJsonSupport}
import org.slf4j.LoggerFactory

import scala.concurrent.ExecutionContext.Implicits.global

/**
  * 自定义的长连接客户端
  */
abstract class SjtpAtmosphereClient extends AtmosphereClient {
  val subscription = new util.HashSet[String]()
}

protected object SjtpAtmosphereClient {
  private val logger = LoggerFactory.getLogger(classOf[SjtpAtmosphereClient])
  //订阅主题的uuid集合
  val uuidMap = Collections.synchronizedMap(new util.HashMap[String, SjtpAtmosphereClient]())
  val tccglFilter: ClientFilter = new MyClientFilter("tccgl")

  class MyClientFilter(topic: String) extends ClientFilter(null) {
    override def apply(v1: AtmosphereResource): Boolean = {
      logger.debug("atmosphere resource uuid={}", v1.uuid())
      uuidMap.get(v1.uuid()).subscription.contains(topic)
    }
  }

}

class ChatController extends ScalatraServlet
  with JValueResult
  with JacksonJsonSupport with SessionSupport
  with AtmosphereSupport {

  private val logger = LoggerFactory.getLogger(classOf[ChatController])

  implicit protected val jsonFormats: Formats = DefaultFormats


  get("/message") {
    AtmosphereClient.broadcast("/socket/ws", ("type" -> "uuid") ~ ("uuid" -> ""), SjtpAtmosphereClient.tccglFilter)

    "send message to client"
  }


  atmosphere("/ws") {

    new SjtpAtmosphereClient {

      def receive: AtmoReceive = {
        case Connected =>
          logger.info("Client {} is connected", uuid)
          subscription.add("tccgl") //默认订阅 tccgl
          SjtpAtmosphereClient.uuidMap.put(uuid, this)
          send(("type" -> "uuid") ~ ("uuid" -> uuid))

        case Disconnected(ClientDisconnected, _) =>
          logger.warn("the client of uuid=%s for subscript %s close connection by client".format(subscription, uuid))
          subscription.clear()
          SjtpAtmosphereClient.uuidMap.remove(uuid)

        case Disconnected(ServerDisconnected, _) =>
          logger.warn("the client of uuid=%s for subscript %s close connection by server".format(subscription, uuid))
          subscription.clear()
          SjtpAtmosphereClient.uuidMap.remove(uuid)

        case TextMessage(text) =>
          logger.debug("recv text message by uuid=%s, message=%s".format(uuid, text))
          send(("message" -> "错误的消息格式") ~ ("type" -> "error"))

        case JsonMessage(json) =>
          logger.debug("recv json message:{}", compact(render(json)))
          compact(render(json \ "type")) match {
            case "ping" => ping(this, json)
            case "pong" => pong(this, json)
            case "subscribe" => subscribe(this, json)
            case "unsubscribe" => unsubscribe(this, json)
          }
      }
    }
  }

  error {
    case t: Throwable => t.printStackTrace()
  }

  notFound {
    // remove content type in case it was set through an action
    contentType = null
  }

  def ping(self: SjtpAtmosphereClient, json: JValue) = {}

  def pong(self: SjtpAtmosphereClient, json: JValue) = {}

  def subscribe(self: SjtpAtmosphereClient, json: JValue) = {}

  def unsubscribe(self: SjtpAtmosphereClient, json: JValue) = {}
}
